﻿using dTools;
using dTools.Extensions;
using EasyLP.Client.Entity;
using EasyLP.Common;
using HPSocket;
using HPSocket.Tcp;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace EasyLP.Client
{
    public partial class FrmMain : Form
    {
        static ITcpPackClient _client = new TcpPackClient();
        private ConfigInfo _configInfo;
        private double _totalLength;

        public FrmMain(ConfigInfo configInfo)
        {
            InitializeComponent();
            _configInfo = configInfo;
            this.Text += $" | {_configInfo.Desc}/{_configInfo.ServerIp}:{_configInfo.Port} | design by HandLoong";
            _configInfo = configInfo;
        }

        /// <summary>
        /// 连接服务器
        /// 获取文件夹
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnConnect_Click(object sender, EventArgs e)
        {
            // 缓冲区大小
            _client.SocketBufferSize = 4096; // 4K
            // 异步连接
            _client.Async = true;

            // pack模型专有设置
            _client.MaxPackSize = 4194303;     // 最大封包
            _client.PackHeaderFlag = 0x01;  // 包头标识, 要与客户端对应, 否则无法通信


            // 要连接的服务器地址和端口(也可以调用Connect()方法时传入服务器ip和端口)
            // 例如: _client.Connect("127.0.0.1", 555)
            _client.Address = _configInfo.ServerIp;
            _client.Port = (ushort)_configInfo.Port;
            var connectRes = _client.Connect();
            if (!connectRes && !_client.IsConnected)
            {
                ShowMsg($"连接失败,请重启软件重试。", Color.Red);
                return;
            }
            else
            {
                ShowMsg($"连接成功,请点击发布", Color.Green);
            }
            btnConnect.Enabled = false;
            _client.OnConnect += _client_OnConnect;
            _client.OnReceive += _client_OnReceive;

            Thread.Sleep(500);
            Send(new PostDataEntity { Type = PacketType.C2S_ACKAPP, AppBasePath = _configInfo.AppBasePath });
        }

        /// <summary>
        /// 连接事件
        /// </summary>
        /// <param name="sender"></param>
        /// <returns></returns>
        private HandleResult _client_OnConnect(IClient sender)
        {
            return HandleResult.Ok;
        }

        /// <summary>
        /// 接收事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        private HandleResult _client_OnReceive(IClient sender, byte[] data)
        {
            var packet = Encoding.UTF8.GetString(data).ToObject<PostDataEntity>();
            switch (packet.Type)
            {
                case PacketType.C2S_Begin:
                    break;
                case PacketType.C2S_AppendFile:
                    if (_totalLength == 0)
                    {
                        lblReceive.BeginInvoke(new Action(() =>
                        {
                            lblReceive.ForeColor = Color.Red;
                            lblReceive.Text = $"接收进度 101%";
                        }));
                    }
                    else
                    {
                        var receive = Math.Round(packet.Receive / _totalLength, 2) * 100;
                        lblReceive.BeginInvoke(new Action(() => { lblReceive.Text = $"接收进度 {receive}%"; }));
                    }
                    //服务器接收量
                    break;
                case PacketType.C2S_FileOk:
                    break;
                case PacketType.S2C_Echo:
                    var color = packet.Msg.Contains("successful") ? Color.Green : Color.Black;
                    if (_configInfo.ShowCMd)
                    {
                        ShowMsg(packet.Msg, color);
                    }
                    if (packet.Msg.Contains("successful"))
                    {
                        ShowMsg($"恭喜！恭喜！发布成功!本次发布耗时：{(DateTime.Now - BeginPublishDate).TotalSeconds} Seconds", color);
                    }
                    break;
                case PacketType.S2C_ACKAPP:
                    cboFolder.Invoke(new Action(() =>
                    {
                        cboFolder.Items.Clear();
                        cboFolder.Items.AddRange(packet.Folder);
                    }));
                    break;
                default:
                    break;
            }
            return HandleResult.Ok;
        }

        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="type"></param>
        /// <param name="data"></param>
        static void Send(PostDataEntity data)
        {
            if (!_client.HasStarted)
            {
                return;
            }
            var bytes = Encoding.UTF8.GetBytes(data.ToJson());

            // 发送数据到服务器
            if (!_client.Send(bytes, bytes.Length))
            {
                _client.Stop();
            }
        }

        /// <summary>
        /// 发布
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnPublish_Click(object sender, EventArgs e)
        {
            var fileName = txtZip.Text;
            var centerName = cboFolder.Text;
            if (fileName == "③ZIP拖过来" && !File.Exists(fileName))
            {
                ShowMsg($"文件不存在,请重新拖放", Color.Red);
                return;
            }
            if (centerName.IsEmpty())
            {
                ShowMsg($"请先选择要发布的文件夹", Color.Red);
                return;
            }

            string keyValue = $"{centerName.Split("Center")[0]}Center";
            if (!_configInfo.WindowsOS)
                keyValue = centerName.Split('.')[0];

            //检查是不是发布错了。
            if (!this.LikePath(centerName, fileName))
            {
                if (MessageBox.Show($@"
Are U 眼花？？？
Are U 眼花？？？
Are U 眼花？？？
Are U 眼花？？？

zip路径:{txtZip.Text}
发布文件夹:{keyValue}
是否选错？？？
继续吗？
", "Tips", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
                {
                    ShowMsg($"发布取消", Color.Blue);
                    return;
                }
            }

            txtLog.Text = "";
            Task.Run(() =>
            {
                Upload(fileName, centerName, ConfigHelper.Account);
            });
            ShowMsg($"发布中..", Color.Blue);
            btnPublish.Enabled = false;
        }
        private DateTime BeginPublishDate = DateTime.Now;

        /// <summary>
        /// 上传
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="centerName"></param>
        /// <param name="account"></param>
        private void Upload(string fileName, string centerName, string account)
        {
            BeginPublishDate = DateTime.Now;
            var total = File.ReadAllBytes(fileName);
            _totalLength = (double)total.Length;
            //每次发 2 M
            var onece = 1024 * 1024 * 2;
            double sended = 0;
            Send(new PostDataEntity { Type = PacketType.C2S_Begin, Msg = "开始发送", Account = account });
            lblReceive.BeginInvoke(new Action(() => { lblReceive.Text = $"接收进度 0%"; }));
            while (total.Length > sended)
            {
                var send = total.ToList().Skip(Convert.ToInt32(sended)).Take(onece).ToArray();
                Send(new PostDataEntity { Type = PacketType.C2S_AppendFile, FileBytes = send, Account = account });
                var s = total.Length - sended;//剩余
                //够不够一次发的
                if (s >= onece)
                    sended += onece;
                else
                    sended += s;

                var percent = Math.Round(sended / _totalLength, 2) * 100;
                lblPersent.BeginInvoke(new Action(() => { lblPersent.Text = $"发布进度 {percent}%"; }));
                if (percent == 100)
                {
                    ShowMsg($"数据传输完成,等待服务器相应...", Color.Blue);
                    this.txtLog.Invoke(new EventHandler(delegate
                    {
                        txtLog.Focus();
                    }));

                }
            }
            Send(new PostDataEntity { Type = PacketType.C2S_FileOk, Msg = "发送完成", CenterName = centerName, Account = account, WindowsOS = _configInfo.WindowsOS, AppBasePath = _configInfo.AppBasePath });
            this.BeginInvoke(new Action(() => { btnPublish.Enabled = true; }));
        }

        /// <summary>
        /// 输出消息
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="color"></param>
        private void ShowMsg(string msg, Color color)
        {
            if (txtLog.InvokeRequired)
            {
                txtLog.Invoke(new Action(() =>
                {
                    txtLog.Write(msg, color);
                }));
            }
            else
            {
                txtLog.Write(msg, color);
            }
        }

        /// <summary>
        /// 拖拽
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void txtZip_DragDrop(object sender, DragEventArgs e)
        {
            string path = ((System.Array)e.Data.GetData(DataFormats.FileDrop)).GetValue(0).ToString();
            var fileInfo = new FileInfo(path);
            if (fileInfo.Extension.ToUpper() == ".ZIP")
            {
                txtZip.Text = fileInfo.FullName;
                //Auto Checked
                var foldersCount = cboFolder.Items.Count;

                fileInfo.FullName.Split('\\').ToList().ForEach(x =>
                {
                    for (int i = 0; i < foldersCount; i++)
                    {
                        if (this.LikePath(cboFolder.Items[i].ToString(), x))
                            cboFolder.Text = cboFolder.Items[i].ToString();
                    }
                });

            }
        }

        private void txtZip_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
                e.Effect = DragDropEffects.All;
            else
                e.Effect = DragDropEffects.None;
        }

        /// <summary>
        /// 应用重启
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tsRestart_Click(object sender, EventArgs e)
        {
            Application.Restart();
        }

        private void supervisorStatusToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Process.Start($"http://{_configInfo.ServerIp}:9001/");
        }

        private void swaggerToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Process.Start($"http://{_configInfo.ServerIp}:8000/swagger");
        }

        private void consulToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Process.Start("http://10.32.44.29:8500/");
        }

        private void baizeHomeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Process.Start($"http://{_configInfo.ServerIp}/");
        }

        /// <summary>
        /// 关闭应用
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FrmMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            Application.Exit();
        }

        private void lblGetDir_Click(object sender, EventArgs e)
        {
            Send(new PostDataEntity { Type = PacketType.C2S_ACKAPP });
        }

        /// <summary>
        /// 连接-加载
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FrmMain_Load(object sender, EventArgs e)
        {
            //btnConnect_Click(sender, null);
        }

        /// <summary>
        /// 包含
        /// </summary>
        /// <param name="cboFolder">选择的文件夹</param>
        /// <param name="fileName">路径地址</param>
        /// <returns></returns>
        private bool LikePath(string cboFolder, string fileName)
        {
            string keyValue = $"{cboFolder.Split("Center")[0]}Center";
            if (!_configInfo.WindowsOS)
                keyValue = cboFolder.Split('.')[0];

            return fileName.Contains(keyValue);
        }

        private void 启动新实例ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var currentExe = Application.ExecutablePath;
            Process.Start(currentExe);
        }
    }
}
